import gp.*;
import ui.*;

import java.awt.Button;
import java.awt.Label;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Event;




/**
 * This is the modal dialog for inspecting and editing some properties of the
 * genetic algorithm.
 * 
 * @version 1.0
 * @author Hans U. Gerber (<a
 *         href="mailto:gerber@ifh.ee.ethz.ch">gerber@ifh.ee.ethz.ch</a>)
 */
public class SettingsDialog extends Dialog {
	private GP gp;
	private Button okButton;
	private Button cancelButton;
	private Label status;

	private void addNumberField(NumberUI param, int x, int y) {
		addComponent(new Label(param.getLabel(), Label.RIGHT), new Rectangle(x - 143, y, 140, 14));
		addComponent(param, new Rectangle(x, y, 30, 14));
		addComponent(new Label("(" + param.getMin() + " ... " + param.getMax() + ")"), new Rectangle(x + 40, y, 50, 14));
	}

	private void addChoiceField(ChoiceUI param, int x, int y) {
		addComponent(new Label(param.getLabel(), Label.RIGHT), new Rectangle(x - 143, y, 140, 14));
		addComponent(param, new Rectangle(x, y, 90, 14));
	}

	/**
	 * Creates the dialog with all its components. Note that the dialog uses
	 * Microsoft's DialogLayout manager. All coordinates are measured in
	 * "Dialog Units", a measure based on the font size.
	 * @param parent
	 * @param gp
	 */
	SettingsDialog(Frame parent, GP gp) {
		super(parent, new Rectangle(8, 8, 280, 282), "GP Settings", true);
		// Weird: The AWT is supposed to make the dialog window a child
		// of the main frame. But it takes the desktop top left corner
		// as coordinate origin instead of the frame's.
		// On some systems, modal dialogs are fixed on the screen, therefore,
		// I have to put my dialog near the top left corner, so that it is fully
		// visible.
		this.gp = gp;
		setResizable(false);

		okButton = new Button("OK");
		addComponent(okButton, new Rectangle(5, 236, 50, 14));
		cancelButton = new Button("Cancel");
		addComponent(cancelButton, new Rectangle(60, 236, 50, 14));

		addNumberField(gp.populationSize, 140, 3);
		addNumberField(gp.maxDepthForNewIndividuals, 140, 18);
		addNumberField(gp.crossoverFraction, 140, 33);
		addNumberField(gp.fitnessProportionateReproFraction, 140, 48);
		addNumberField(gp.mutationFraction, 140, 63);
		addNumberField(gp.maxDepthForIndividualsAfterCrossover, 140, 78);
		addNumberField(gp.maxDepthForNewSubtreesInMutants, 140, 93);
		addChoiceField(gp.methodOfGeneration, 140, 108);
		addChoiceField(gp.methodOfSelection, 140, 123);

		addComponent(new Label(gp.trainingData.getLabel()), new Rectangle(5,140, 50, 12));
		addComponent(gp.trainingData, new Rectangle(5, 152, 98, 65));
		addComponent(new Label(gp.functionSet.getLabel()), new Rectangle(110,140, 50, 12));
		addComponent(gp.functionSet, new Rectangle(110, 152, 80, 65));

		addComponent(new Label(gp.terminalSet.getLabel()), new Rectangle(195,140, 50, 12));
		addComponent(gp.terminalSet, new Rectangle(195, 152, 80, 65));

		status = new Label();
		addComponent(status, new Rectangle(5, 222, 240, 10));
	}

	/**
	 * Is called whenever the user clicks a command button. On the "OK" button,
	 * the dialog validates all its fields. If any field is found invalid, the
	 * error message returned by the offending component is displayed. If all
	 * fields are valid, their contents are accepted.
	 * @return boolean result
	 */
	public boolean action(Event evt, Object what) {
		if (evt.target == okButton) {
			String validateMsg = onApply();
			if (validateMsg == null) {
				status.setText("");
			} else {
				status.setText(validateMsg);
			}
			return true;
		}
		if (evt.target == cancelButton) {
			onCancel();
			return true;
		}
		return false;
	}

	public String onApply() {
		String result = super.onApply();
		if (result == null) {
			gp.settingsChanged();
		}
		return result;
	}

}
